/**
 * 字典
 */
export class Dic<T> {
  protected table: { [key: string]: T };

  constructor(entries?: [string, T][]) {
    this.table = {};
    if (entries) {
      entries.forEach((f) => {
        this.set(f[0], f[1]);
      });
    }
  }

  /** 设置键和值
   *
   * @param key 键
   * @param value 值
   */
  set(key: string, value: T) {
    return (this.table[key] = value);
  }

  /** 根据键值取值
   *
   * @param key 键值
   * @returns 返回value
   */
  get(key: string) {
    return this.table[key];
  }

  /**字典里元素数量
   *
   * @returns
   */
  size(): number {
    let n = 0;
    for (const key in this.table) {
      if (this.table.hasOwnProperty(key)) {
        n++;
      }
    }
    return n;
  }

  /** 清除字典里元素
   *
   */
  clear() {
    this.table = {};
  }

  /**按键值清除元素
   *
   * @param key 键值
   * @returns 返回该元素
   */
  remove(key: string) {
    const v = this.table[key];
    delete this.table[key];
    return v;
  }

  /** 是否为空字典
   *
   * @returns boolean
   */
  isEmpty(): boolean {
    return this.size() < 1;
  }

  /** 字典是否包含key
   *
   * @param key 键值
   * @returns boolean
   */
  containsKey(key: string): boolean {
    return this.table.hasOwnProperty(key);
  }

  forEach(callback: (key: string, value: T) => any): void {
    for (const name in this.table) {
      if (this.table.hasOwnProperty(name)) {
        const ret = callback(name, this.table[name]);
        if (ret === false) {
          return;
        }
      }
    }
  }

  /** 返回键值集合
   *
   * @returns 返回键值集合
   */
  keys(): string[] {
    const arr: string[] = [];
    for (const key in this.table) {
      if (this.table.hasOwnProperty(key)) {
        arr.push(key);
      }
    }
    return arr;
  }

  /** 返回值集合
   *
   * @returns 返回值集合
   */
  values(): T[] {
    const arr: T[] = [];
    for (const key in this.table) {
      if (this.table.hasOwnProperty(key)) {
        arr.push(this.table[key]);
      }
    }
    return arr;
  }
}
